﻿using Abide_AddOn_API;
using Abide_AddOn_API.Interfaces;
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;

namespace Abide.Classes
{
    public class AbideAddOnManager : MarshalByRefObject, IAddOnHost
    {
        public bool InvokeRequired
        {
            get
            {
                return owner.InvokeRequired;
            }
        }
        public static Dictionary<string, AddOnFactory> Collections
        {
            get;
            protected set;
        }

        static AbideAddOnManager()
        {
            Collections = new Dictionary<string, AddOnFactory>();
        }
        private readonly Control owner;
        private readonly Abide_Halo_Library.Halo_2_Map.Halo2Map halo2Map;
        private readonly Abide_Halo_Library.Halo_2_Beta_Map.Halo2BetaMap halo2BetaMap;
        private Abide_Halo_Library.Halo_2_Map.IndexEntry halo2Entry;
        private Abide_Halo_Library.Halo_2_Beta_Map.IndexEntry halo2BetaEntry;
        private event EventHandler reloadMap;

        /// <summary>
        /// Occurs when a client AddOn requests a reload of the Map.
        /// </summary>
        public event EventHandler ReloadMap
        {
            add { reloadMap += value; }
            remove { reloadMap -= value; }
        }

        public AbideAddOnManager(Control owner, Abide_Halo_Library.Halo_2_Map.Halo2Map Map)
        {
            //Setup
            this.halo2Map = Map;
            this.owner = owner;
        }
        public AbideAddOnManager(Control owner, Abide_Halo_Library.Halo_2_Beta_Map.Halo2BetaMap Map)
        {
            //Setup
            this.halo2BetaMap = Map;
            this.owner = owner;
        }
        public void SetEntry(Abide_Halo_Library.Halo_2_Map.IndexEntry entry)
        {
            //Set Field
            halo2Entry = entry;
        }
        public void SetEntry(Abide_Halo_Library.Halo_2_Beta_Map.IndexEntry entry)
        {
            //Set Field
            halo2BetaEntry = entry;
        }
        public object SendCommand(object sender, string command, params string[] args)
        {
            //Prepare
            string type = string.Empty;
            string EntFile = string.Empty;

            //Handle Command
            switch (command)
            {
                case "ReloadMap":
                    reloadMap?.Invoke(this, new EventArgs());
                    break;

                case "GetHalo2Map":
                    return halo2Map;

                case "GetHalo2BetaMap":
                    return halo2BetaMap;

                case "GetHalo2IndexEntry":
                    return halo2Entry;

                case "GetHalo2BetaIndexEntry":
                    return halo2BetaEntry;

                case "GetXbox":
                    return Program.Xbox;

                case "GetPlugin":
                    type = string.Empty;
                    if (args.Length > 0)
                        type = args[0];
                    else
                        //Get SelectedEntry Class...
                        if (halo2Entry != null)
                        {
                            if (halo2Entry != null)
                                type = halo2Entry.Class;
                        }
                        else if (halo2BetaEntry != null)
                        {
                            if (halo2BetaEntry != null)
                                type = halo2BetaEntry.Class;
                        }

                    //Find File and Return
                    if (halo2Map != null)
                    {
                        //Format Class for Ent File Name
                        EntFile = string.Format("{0}.ent", type).Replace('<', '_').Replace('>', '_').Trim();
                        return new Abide_AddOn_API.Meta.HaloPlugin(System.IO.Path.Combine(Abide_AddOn_API.Classes.Settings.H2_PluginsPath, EntFile));
                    }
                    else if (halo2BetaMap != null)
                    {
                        //Format Class for Ent File Name
                        EntFile = string.Format("{0}.ent", type).Replace('<', '_').Replace('>', '_').Trim();
                        return new Abide_AddOn_API.Meta.HaloPlugin(System.IO.Path.Combine(Abide_AddOn_API.Classes.Settings.H2B_PluginsPath, EntFile));
                    }
                    else
                        return null;
            }

            //Return Null
            return null;
        }
        public object Invoke(Delegate method)
        {
            //Invoke
            return owner.Invoke(method);
        }
        public object Invoke(Delegate method, params object[] args)
        {
            //Invoke
            return owner.Invoke(method, args);
        }

        public static void LoadAssembly(string safeName, string Folder, string assemblyFile)
        {
            //Check
            AddOnFactory Factory = null;

            //Get
            if (!Collections.ContainsKey(Folder))
            {
                //Create an AddOn Factory
                Factory = new AddOnFactory();
                Factory.AddOnDirectory = Folder;

                //Add
                Collections.Add(Folder, Factory);
            }
            else
                Factory = Collections[Folder];  //Get Collection

            try
            {
                //Get Types
                Factory.LoadAssembly(assemblyFile);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        public static void DirectLoadAssembly(string assemblyFile)
        {
            //Check
            AddOnFactory Factory = null;
            string Folder = Path.GetDirectoryName(assemblyFile);

            //Get
            if (!Collections.ContainsKey(assemblyFile))
            {
                //Create Factory
                Factory = new AddOnFactory();
                Factory.AddOnDirectory = Folder;

                //Add
                Collections.Add(Folder, Factory);
            }
            else
                Factory = Collections[assemblyFile];
            
            try
            {
                //Get Types
                Factory.LoadAssembly(assemblyFile);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }
        }
        public static bool IsAddOn(string assemblyFile)
        {
            //Prepare
            bool result = false;

            try
            {
                //Create Factory
                AddOnFactory Factory = new AddOnFactory();
                Factory.LoadAssemblySafe(assemblyFile);

                //Check
                if (Factory.FoundTypes.Count > 0)
                    result = true;
            }
            catch { result = false; }
            return result;
        }
        public static bool VersionMatch(IAddOn addOn)
        {
            //Get
            Version Abide = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
            Version AddOn = addOn.AbideVersion;

            //Compare
            if (AddOn.Major == Abide.Major && AddOn.Minor == Abide.Minor)
                return true;
            return false;
        }
    }

    public struct AddOnInformation
    {
        public string FileLocation;
        public string DirectoryLocation;
        public string InterfaceName;
    }
}
